package com.metal.gear.common.util.query;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.metal.gear.common.util.HumpUtil;


import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

public class SearchHelper {

    public static <T, S> QueryWrapper<T> generalQueryWrapper(S searchObj) throws Exception {
        QueryWrapper<T> queryWrapper = new QueryWrapper<T>();
        List<SearchRule> searchRules = doAnalysisSearchObj(searchObj);
        doGeneral(queryWrapper, searchRules);
        return queryWrapper;
    }


    private static <S> List<SearchRule> doAnalysisSearchObj(S searchObj) throws Exception {
        //1.反射获取该类和其父类所有的Field
        List<Field> searchObjFieldList = listQueryRuleFields(searchObj.getClass());
        //2.获取该类所有的属性
        //PropertyDescriptor[] propertyDescriptors = PropertyUtils.getPropertyDescriptors(searchObj);
        //3.分析所有的属性，获取配置wrapper需要的数据
        List<SearchRule> result = new ArrayList<>();
        for (Field field : searchObjFieldList) {
            List<String> tableColumn = generalTableColumn(field);
            Object columnValue = generalColumnValue(searchObj, field);
            QueryRuleEnum matchMethod = generalMatchMethod(field);
            result.add(new SearchRule(tableColumn, columnValue, matchMethod));
        }
        return result;
    }


    private static List<String> generalTableColumn(Field usableField) {
        QueryRule queryRule = usableField.getAnnotation(QueryRule.class);
        if (queryRule.column().length == 0) {
            return Arrays.asList(HumpUtil.HumpToUnderline(usableField.getName()));
        } else {
            return Arrays.stream(queryRule.column())
                    .map(HumpUtil::HumpToUnderline)
                    .collect(Collectors.toList());
        }
    }

    private static QueryRuleEnum generalMatchMethod(Field usableField) {
        return usableField.getAnnotation(QueryRule.class).queryCondition();
    }

    private static <S> Object generalColumnValue(S searchObj, Field field) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        field.setAccessible(true);
        return field.get(searchObj);
    }


    /**
     * 获取class的 包括父类的
     *
     * @param clazz
     * @return
     */
    private static List<Field> listQueryRuleFields(Class<?> clazz) {
        List<Field> list = new ArrayList<Field>();
        Field[] fields;
        do {
            fields = clazz.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                if (Objects.nonNull(fields[i].getAnnotation(QueryRule.class))) {
                    list.add(fields[i]);
                }
            }
            clazz = clazz.getSuperclass();
        } while (clazz != Object.class && clazz != null);
        return list;
    }


    private static <T> void doGeneral(QueryWrapper<T> queryWrapper,
                                      List<SearchRule> searchRuleList) {
        for (SearchRule searchRule : searchRuleList) {
            List<String> tableColumnList = searchRule.getTableColumn();
            QueryRuleEnum matchMethod = searchRule.getMatchMethod();
            Object columnValue = searchRule.getColumnValue();
            for (String tableColumn : tableColumnList) {
                if (columnValue == null) {
                    continue;
                }
                switch (matchMethod) {
                    case GT:
                        queryWrapper.gt(tableColumn, columnValue);
                        break;
                    case GE:
                        queryWrapper.ge(tableColumn, columnValue);
                        break;
                    case LT:
                        queryWrapper.lt(tableColumn, columnValue);
                        break;
                    case LE:
                        queryWrapper.le(tableColumn, columnValue);
                        break;
                    case EQ:
                    case EQ_WITH_ADD:
                        queryWrapper.eq(tableColumn, columnValue);
                        break;
                    case NE:
                        queryWrapper.ne(tableColumn, columnValue);
                        break;
                    case IN:
                        if (columnValue instanceof String) {
                            queryWrapper.in(tableColumn, (Object[]) columnValue.toString().split(","));
                        } else if (columnValue instanceof String[]) {
                            queryWrapper.in(tableColumn, (Object[]) columnValue);
                        }
                        //update-begin-author:taoyan date:20200909 for:【bug】in 类型多值查询 不适配postgresql #1671
                        else if (columnValue.getClass().isArray()) {
                            queryWrapper.in(tableColumn, (Object[]) columnValue);
                        } else {
                            queryWrapper.in(tableColumn, columnValue);
                        }
                        //update-end-author:taoyan date:20200909 for:【bug】in 类型多值查询 不适配postgresql #1671
                        break;
                    case SOME_ONE_IN:
                        if (columnValue instanceof String) {
                            queryWrapper.and((wrapper) -> {
                                for (String oneColumnValue : ((String) columnValue).split(",")) {
                                    wrapper.like(tableColumn, oneColumnValue).or();
                                }
                            });
                        } else if (columnValue instanceof String[]) {
                            queryWrapper.and((wrapper) -> {
                                for (String oneColumnValue : (String[]) columnValue) {
                                    wrapper.like(tableColumn, oneColumnValue).or();
                                }
                            });
                        } else if (columnValue.getClass().isArray()) {
                        } else {
                        }

                        break;
                    case LIKE:
                        queryWrapper.like(tableColumn, columnValue);
                        break;
                    case LEFT_LIKE:
                        queryWrapper.likeLeft(tableColumn, columnValue);
                        break;
                    case RIGHT_LIKE:
                        queryWrapper.likeRight(tableColumn, columnValue);
                        break;
                    default:
                        break;
                }

            }

        }

    }
}
